﻿using System.Windows.Input;
using System.Windows;
using System;
using System.Windows.Controls;

namespace PlanetWPF.Toolbelt.Utils
{
    /// <summary>
    /// This class wraps a <see cref="CommandBinding"/> in a 
    /// <see cref="DependencyObject"/>, allowing for databinding its properties.
    /// </summary>
    public class CommandBindingAdapter : DependencyObject
    {
        /// <summary>
        /// Gets or sets the <see cref="ICommand"/> associated with the CommandBinding
        /// </summary>
        public static readonly DependencyProperty CommandProperty;

        /// <summary>
        /// Gets or sets the <see cref="CanExecuteRoutedEventHandler"/> associated
        /// with this <see cref="CommandBinding"/>.
        /// </summary>
        public static readonly DependencyProperty CanExecuteProperty;

        /// <summary>
        /// Gets or sets the <see cref="ExecutedRoutedEventHandler"/>
        /// associated with the CommandBinding.
        /// </summary>
        public static readonly DependencyProperty ExecutedProperty;

        /// <summary>
        /// Use to add a <see cref="CommandBindingAdapter"/> to a control.
        /// </summary>
        public static readonly DependencyProperty AttachCommandProperty;

        static CommandBindingAdapter()
        {
            AttachCommandProperty =
                DependencyProperty.RegisterAttached
                (
                    "AttachCommand",
                    typeof(CommandBindingAdapter),
                    typeof(CommandBindingAdapter),
                    new FrameworkPropertyMetadata(null, new PropertyChangedCallback(AttachCommandBinding))
                );
            CanExecuteProperty =
                DependencyProperty.Register
                (
                    "CanExecute",
                    typeof(CanExecuteRoutedEventHandler),
                    typeof(CommandBindingAdapter),
                    new FrameworkPropertyMetadata(null)
                );

            CommandProperty =
                DependencyProperty.Register
                (
                    "Command",
                    typeof(ICommand),
                    typeof(CommandBindingAdapter),
                    new FrameworkPropertyMetadata(null)
                );
            ExecutedProperty =
                DependencyProperty.Register
                (
                    "Executed",
                    typeof(ExecutedRoutedEventHandler),
                    typeof(CommandBindingAdapter),
                    new FrameworkPropertyMetadata(null)
                );                                                      

        }

        private static void AttachCommandBinding(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = d as Control;
            var adapter = e.NewValue as CommandBindingAdapter;
            if(control!=null&& adapter!=null)
            {
                control.CommandBindings.Add(adapter);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="control"></param>
        /// <param name="adapter"></param>
        public static void SetAttachCommand(Control control, CommandBindingAdapter adapter)
        {
            control.SetValue(AttachCommandProperty, adapter);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="control"></param>
        /// <returns></returns>
        public static CommandBindingAdapter GetAttachCommand(Control control)
        {
            return (CommandBindingAdapter) control.GetValue(AttachCommandProperty);
        }

        /// <summary>
        /// A property wrapper for the <see cref="CanExecuteProperty"/>
        /// dependency property:<br/>
        /// Gets or sets the <see cref="CanExecuteRoutedEventHandler"/> associated
        /// with this <see cref="CommandBinding"/>.
        /// </summary>
        public CanExecuteRoutedEventHandler CanExecute
        {
            get { return (CanExecuteRoutedEventHandler) GetValue(CanExecuteProperty); }
            set { SetValue(CanExecuteProperty, value); }
        }

        /// <summary>
        /// A property wrapper for the <see cref="CommandProperty"/>
        /// dependency property:<br/>
        /// Gets or sets the <see cref="ICommand"/> associated with the CommandBinding.
        /// </summary>
        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        /// <summary>
        /// A property wrapper for the <see cref="ExecutedProperty"/>
        /// dependency property:<br/>
        /// Gets or sets the <see cref="ExecutedRoutedEventHandler"/>
        /// associated with the CommandBinding.
        /// </summary>
        public ExecutedRoutedEventHandler Executed
        {
            get { return (ExecutedRoutedEventHandler) GetValue(ExecutedProperty); }
            set { SetValue(ExecutedProperty, value); }
        }

        /// <summary>
        /// Implicitly casts a <see cref="CommandBindingAdapter"/> to a
        /// <see cref="CommandBinding"/>
        /// </summary>
        /// <param name="obj">
        /// The <see cref="CommandBindingAdapter"/> to cast.
        /// </param>
        /// <returns>
        /// A new <see cref="CommandBinding"/> that is equivalent to the 
        /// <see cref="CommandBindingAdapter"/> being cast.
        /// </returns>
        public static implicit operator CommandBinding(CommandBindingAdapter obj)
        {
            return new CommandBinding(obj.Command, obj.Executed, obj.CanExecute);

        }
    }
}
